package cn.weekdragon.gscore.adapter;

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.util.StatusPrinter;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.weekdragon.gscore.adapter.bot.Bot;
import cn.weekdragon.gscore.adapter.bot.BotManager;
import cn.weekdragon.gscore.adapter.bot.impl.RedBot;
import cn.weekdragon.gscore.adapter.filter.BotFilter;
import cn.weekdragon.gscore.adapter.filter.impl.KeywordBlockFilter;
import cn.weekdragon.gscore.adapter.filter.impl.StripPrefixFilter;
import cn.weekdragon.gscore.adapter.model.enums.ProtocolEnum;
import cn.weekdragon.gscore.adapter.predicate.BotPredicate;
import cn.weekdragon.gscore.adapter.predicate.impl.PatternPredicate;
import cn.weekdragon.gscore.adapter.predicate.impl.PrefixPredicate;
import cn.weekdragon.gscore.adapter.predicate.impl.SuffixPredicate;
import cn.weekdragon.gscore.adapter.route.Route;
import cn.weekdragon.gscore.adapter.route.RouteManager;
import cn.weekdragon.gscore.adapter.service.Service;
import cn.weekdragon.gscore.adapter.service.ServiceManager;
import cn.weekdragon.gscore.adapter.service.impl.GsCoreService;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import java.io.FileReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.StringJoiner;

@Slf4j
public class Main {

    public static void main(String[] args) throws Exception {
        initLogger();
        initConfig();
        initBots();
        initServices();
        initRoutes();
        loop();
    }

    private static void initLogger() {
        // 创建 LoggerContext，并通过 JoranConfigurator 加载 logback.xml 配置文件
        LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
        context.reset();
        JoranConfigurator configurator = new JoranConfigurator();
        configurator.setContext(context);
        try {
            configurator.doConfigure("logback.xml");
        } catch (Exception e) {
            // 配置加载失败
            throw new RuntimeException("配置加载失败：", e);
        }
        log.info("日志配置加载成功");
//        StatusPrinter.print(context);
        // 打印 Logback 内部状态，可以检查配置是否成功加载
        StatusPrinter.printInCaseOfErrorsOrWarnings(context);
    }

    private static void initBots() {
        List<GlobalConfig.BotItem> bots = GlobalConfig.ins.getBots();
        StringJoiner sj = new StringJoiner("、");
        if (CollectionUtil.isNotEmpty(bots)) {
            for (GlobalConfig.BotItem bot : bots) {
                try {
                    if (ProtocolEnum.RED.getName().equals(bot.getProtocol())) {
                        RedBot redBot = new RedBot(bot.getWsReverse(), bot.getName(), bot.getAuthorization());
                        redBot.reconnect();
                        BotManager.addBot(redBot);
                        sj.add(redBot.getBotName());
                    }
                } catch (Exception e) {
                    log.error("bot {} 的配置初始化失败：", bot.getName(), e);
                }
            }
        }
        log.info("加载 bot：{}", sj);
    }

    private static void initServices() {
        List<GlobalConfig.ServiceItem> services = GlobalConfig.ins.getServices();
        StringJoiner sj = new StringJoiner("、");
        if (CollectionUtil.isNotEmpty(services)) {
            for (GlobalConfig.ServiceItem service : services) {
                try {
                    if (ProtocolEnum.GS_CORE.getName().equals(service.getProtocol())) {
                        GsCoreService coreService = new GsCoreService(service.getWsReverse(), service.getName(), null);
                        coreService.reconnect();
                        ServiceManager.addService(coreService);
                        sj.add(coreService.getServiceName());
                    }
                } catch (Exception e) {
                    log.error("service {} 的配置初始化失败：", service.getName(), e);
                }
            }
        }
        log.info("加载 service：{}", sj);
    }

    private static void initRoutes() {
        new Thread(() -> {
            List<GlobalConfig.RouteItem> routes = GlobalConfig.ins.getRoutes();
            if (CollectionUtil.isNotEmpty(routes)) {
                for (GlobalConfig.RouteItem item : routes) {
                    Route route = new Route();
                    route.setBot(item.getBot());
                    route.setService(item.getService());
                    route.setPredicates(parsePredicates(item.getPredicates()));
                    route.setBotFilters(parseFilters(item.getFilters()));
                    RouteManager.addRoute(route);
                }
            }
        }).start();
    }

    private static List<BotFilter> parseFilters(List<String> filters) {
        List<BotFilter> botFilters = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(filters)) {
            for (String filterConfig : filters) {
                String[] split = filterConfig.split("=");
                String filterType = split[0];
                if ("StripPrefix".equals(filterType)) {
                    if (split.length < 2) {
                        throw new RuntimeException("filter StripPrefix 缺少 前缀参数");
                    }
                    botFilters.add(new StripPrefixFilter(split[1]));
                }else if("KeywordBlock".equals(filterType)){
                    if (split.length < 2) {
                        throw new RuntimeException("filter KeywordBlock 缺少 前缀参数");
                    }
                    botFilters.add(new KeywordBlockFilter(split[1]));
                }
            }
        }
        return botFilters;
    }

    private static List<BotPredicate> parsePredicates(List<String> predicates) {
        List<BotPredicate> botPredicates = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(predicates)) {
            for (String predicateConfig : predicates) {
                String[] split = predicateConfig.split("=");
                String predicateType = split[0];
                if ("Prefix".equals(predicateType)) {
                    if (split.length < 2) {
                        throw new RuntimeException("predicate Prefix 缺少 参数");
                    }
                    botPredicates.add(new PrefixPredicate(split[1]));
                } else if ("Suffix".equals(predicateType)) {
                    if (split.length < 2) {
                        throw new RuntimeException("predicate Suffix 缺少 参数");
                    }
                    botPredicates.add(new SuffixPredicate(split[1]));
                } else if ("Pattern".equals(predicateType)) {
                    if (split.length < 2) {
                        throw new RuntimeException("predicate Pattern 缺少 参数");
                    }
                    botPredicates.add(new PatternPredicate(split[1]));
                }
            }
        }
        return botPredicates;
    }

    private static void loop() {
        while (true) {
            ThreadUtil.sleep(5000);
            log.info("connect loop...");
            for (Bot bot : BotManager.getBots()) {
                try {
                    bot.reconnect();
                } catch (Exception e) {
                    log.error("bot({}) 重连失败", bot.getBotName(), e);
                }
            }
            for (Service service : ServiceManager.getServices()) {
                try {
                    service.reconnect();
                } catch (Exception e) {
                    log.error("service({}) 重连失败", service.getServiceName(), e);
                }
            }
        }
    }

    private static void initConfig() {
        try {
            Yaml yaml = new Yaml(new Constructor(GlobalConfig.class, new LoaderOptions()));
            GlobalConfig.ins = yaml.load(new FileReader("config.yml", StandardCharsets.UTF_8));
            log.info("加载配置如下\n{}\n\n\n", JSON.toJSONString(GlobalConfig.ins, true));
        } catch (Exception e) {
            log.error("读取配置出错:", e);
            throw new RuntimeException("读取配置出错");
        }
    }

    public static String getENVProperty(Properties properties, String key) {
        return getENVProperty(properties, key, false);
    }

    public static String getENVProperty(Properties properties, String key, boolean force) {
        String value = properties.getProperty(key);
        if (value.startsWith("$")) {
            value = System.getenv(value.substring(2, value.length() - 1));
        }
        if (StrUtil.isEmpty(value)) {
            if (force) {
                throw new RuntimeException("配置 %s 不能为空".formatted(key));
            }
            value = "";
        }
        return value;
    }
}